package com.settlement.system.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.settlement.system.csv.CsvExportBuilder;
import com.settlement.system.csv.CsvExportUtil;
import com.settlement.system.common.enums.ExcelFileType;
import com.settlement.system.common.enums.WpTypeEnum;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.model.entity.common.*;
import com.settlement.system.reply.ObjectDataResponse;
import com.settlement.system.service.*;
import com.settlement.system.service.csv.DateSpiltCsvDatas;
import com.settlement.system.common.util.common.FasUtil;
import com.alibaba.excel.ExcelWriter;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author
 */
@Slf4j
@RestController
@RequestMapping("/wp/summary/")
public class WpSummaryController extends BaseController<WpSummary>{

    @Value("${system.export-root.path}")
    private String exportRootPath;

    @Resource
    private IWpSummaryService iWpSummaryService;

    @Resource
    private ITblWpBillSaleDetailService iTblWpBillDetailService;

    @Resource
    private ITblWpBillReturnDetailService iTblWpBillReturnDetailService;

    @Resource
    private ITblWpBillOtherDetailService iTblWpBillOtherDetailService;

    @Resource
    private ITblWpBillDiscountDetailService iTblWpBillDiscountDetailService;

    @Resource
    private ITblWpManualItemDiffService iTblWpManualItemDiffService;

    @Resource
    private ITblWpItemDiffSourceService iTblWpItemDiffSourceService;

    @Resource
    private ITblWpVendorConfigService iTblWpVendorConfigService;

    @Override
    public IBaseService init() {
        return iWpSummaryService;
    }

    @Override
    protected void setFootModel(Map<String, Object> result, Map<String, Object> model) throws ServiceException {
        WpSummary foot = iWpSummaryService.selectFoot(model);
        result.put("foot",foot);
        super.setFootModel(result, model);
    }

    @GetMapping("export")
    public void export(HttpServletRequest request, HttpServletResponse response) throws  Exception{

        try {
            Map<String,Object> params = buildParam(request);
            setParamsModel(params);
            File file = new File(exportRootPath + "唯品汇总" + System.currentTimeMillis() + "/");
            if(!file.exists()){
                file.mkdirs();
            }

            Set<String> orderTypeSet = getOrderTypes(params.get("orderTypes"));

            List<WpExport> wpExports = new ArrayList<WpExport>();
            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.HZ.name())){
                wpExports.add(submit(iWpSummaryService,file.getAbsolutePath(),"汇总.xlsx",params,WpSummary.class));
            }

            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.XS.name())){
                params.put("orderType",WpTypeEnum.ORDER_TYPE.SALE.getNo());
                wpExports.add(submit(iTblWpBillDetailService,file.getAbsolutePath(),"销售明细.xlsx",params, TblWpBillSaleDetail.class));
                params.put("orderType",WpTypeEnum.ORDER_TYPE.RETURN.getNo());
            }

            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.KT.name())){
                params.put("orderType",WpTypeEnum.ORDER_TYPE.RETURN.getNo());
                wpExports.add(submit(iTblWpBillReturnDetailService,file.getAbsolutePath(),"客退明细.xlsx",params,TblWpBillReturnDetail.class));
            }

            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.QT.name())){
                params.put("orderType",WpTypeEnum.ORDER_TYPE.OTHER.getNo());
                wpExports.add(submit(iTblWpBillOtherDetailService,file.getAbsolutePath(),"其他明细.xlsx",params,TblWpBillOtherDetail.class));
            }

            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.HDZK.name())){
                params.put("orderType",WpTypeEnum.ORDER_TYPE.DISCOUNT.getNo());
                wpExports.add(submit(iTblWpBillDiscountDetailService,file.getAbsolutePath() , "活动折扣.xlsx",params, TblWpBillDiscountDetail.class));
            }

            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.CY.name())){
                params.put("orderType",WpTypeEnum.ORDER_TYPE.DIFF.getNo());
                wpExports.add(submit(iTblWpItemDiffSourceService,file.getAbsolutePath(),"差异明细.xlsx",params, TblWpItemDiffSource.class));
            }

            if(orderTypeSet.contains(WpTypeEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(WpTypeEnum.PAGE_TAB.CYDY.name())){
                params.put("orderType",WpTypeEnum.ORDER_TYPE.DIFF.getNo());
                wpExports.add(submit(iTblWpManualItemDiffService,file.getAbsolutePath(),"差异明细-导.xlsx",params, TblWpManualItemDiff.class));
            }

            for(WpExport info:wpExports){
                info.get();
            }
            File zipFile = getZipFile(file);
            exportFile(request,response,zipFile);
        } catch (Exception ex){
            log.error("唯品导出异常",ex);
            throw ex;
        }
    }

    private Set<String> getOrderTypes(Object orderTypes){
        Set<String> orderTypeSet = new HashSet<>();

        if(orderTypes != null){
            String[] strs = orderTypes.toString().split(",");
            for(int index = 0;index < strs.length;index++){
                orderTypeSet.add(strs[index]);
            }
        }
        if(orderTypeSet.size() == 0){
            orderTypeSet.add("ALL");
        }
        return orderTypeSet;
    }

    /**
     * 打包，生成zip文件
     * @param pathFile
     * @return
     * @throws IOException
     */
    public File getZipFile(File pathFile) throws IOException {
        ZipOutputStream out = null;
        try {
            File zipfile = new File(exportRootPath + "唯品汇总" + System.currentTimeMillis() + "_.zip");
            out = new ZipOutputStream(new FileOutputStream(zipfile));
            byte[] buf = new byte[4096];

            for(File file : pathFile.listFiles()){
                FileInputStream in = null;
                try {
                    in = new FileInputStream(file);
                    out.putNextEntry(new ZipEntry(file.getName()));
                    int len;
                    while( (len = in.read(buf)) > 0){
                        out.write(buf, 0, len);
                    }
                    out.closeEntry();
                } catch (IOException e) {
                    log.info("文件压缩异常",e);
                    throw e;
                } finally {
                    if(in != null){
                        in.close();
                    }
                    if(file != null){
                        file.delete();
                    }
                }
            }
            return zipfile;
        } catch (IOException ex){
            log.info("文件压缩异常",ex);
            throw ex;
        } finally {
            if(out != null){
                out.close();
            }
            deleteDir(pathFile);
        }
    }

    /**
     * 导出文件
     * @param request
     * @param response
     * @param file
     * @throws ServiceException
     */
    public void exportFile(HttpServletRequest request, HttpServletResponse response,File file) throws ServiceException {
        FileInputStream in = null;
        OutputStream out = null;
        try {
            String zipfileName = "wpAccount.zip";
            final String userAgent = "User-Agent";
            final String firefox = "firefox";
            out = response.getOutputStream();
            if(request.getHeader(userAgent).toLowerCase().indexOf(firefox) > 0){
                zipfileName = new String(zipfileName.getBytes("GB2312"),"ISO-8859-1");
            }else {
                zipfileName = java.net.URLEncoder.encode(zipfileName, "UTF-8");
                zipfileName = new String(zipfileName.getBytes("UTF-8"), "GBK");
            }

            out = new ZipOutputStream(response.getOutputStream());
            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment;filename="+zipfileName);

            in = new FileInputStream(file);
            out = response.getOutputStream();
            byte[] buf = new byte[4089];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } catch (Exception e) {
            log.error("导出文件异常",e);
            throw new ServiceException("导出文件异常",e);
        } finally {
            IoUtil.close(in);
            IoUtil.close(out);
            FileUtil.del(file);
            log.info("传输数据完成");
        }
    }

    /**
     * 删除文件夹
     * @param dir
     */
    private static void deleteDir(File dir) {

        if(dir == null) {
            throw new NullPointerException("the dir is null.");
        }

        if(dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {

                if(file.isDirectory()) {
                    deleteDir(file); // 递归删除
                } else {
                    FileUtil.del(file);
                }
            }
            dir.delete();
        }else {
            dir.delete();
        }
    }


    private WpExport submit(IBaseService baseService,String path,String fileName, Map<String,Object> params,Class aclass){
        ForkJoinPool pool = ForkJoinPool.commonPool();
        WpExport wpExport =  new WpExport(baseService,path,fileName,params,aclass);
        pool.submit(wpExport);
        return wpExport;
    }

    /**
     * 唯品导出的任务
     */
    public class WpExport extends RecursiveAction{

        public IBaseService baseService;
        public String fileName;
        public String path;
        public Class aClass;
        public Map<String,Object> params;
        String fileType;
        ExcelWriter excelWriter;
        private Integer singleFileRowsNum = 500000;
        //xlsx的fileName带后缀，csv的不带后缀
        public WpExport(IBaseService baseService,String path,String fileName,Map<String,Object> params,Class aClass){
            this.baseService = baseService;
            this.path = path;
            this.fileName = fileName;
            this.params = (Map<String, Object>) ((HashMap) params).clone();
            this.aClass = aClass;
            checkFileName();
        }

        void checkFileName(){
            this.fileType = (String) this.params.get("fileType");
            if(fileType==null){
                fileType = ExcelFileType.XLSX.toString();
            }

            if(fileName.toLowerCase().endsWith(ExcelFileType.CSV.name().toLowerCase())||fileName.toLowerCase().endsWith(ExcelFileType.XLSX.name().toLowerCase())){
                int pos = fileName.lastIndexOf(".");
                fileName=fileName.substring(0,pos);
            }
        }

        @Override
        protected void compute() {
            try {
                if (baseService.selectCount(params) <= 0) {
                    return;
                }

                CsvExportUtil.createCsv()
                        .headClass(aClass)
                        .fileName(fileName)
                        .fileType(ExcelFileType.getByName(this.fileType))
                        .model(CsvExportBuilder.MULTI_NOT_ZIP_MODEL)
                        .parentPath(path+File.separator)
                        .csvDatas(new DateSpiltCsvDatas(baseService, params))
                        .generateFile();

            } catch (Exception ex){
                ex.printStackTrace();
                completeExceptionally(ex);
            }
        }

        private String excelFileName(int resultCount) {
            return StringUtils.replace(fileName,".","_"+ resultCount /singleFileRowsNum+".");
        }
    }

    @Override
    protected void setParamsModel(Map<String, Object> model) {
        FasUtil.formatInQueryCondition(model,"shopNo","billNumberType","settleAccountPeriod",
                "brandNo","processStatus","categoryName","billNumber","calendar",
                "globalId","so","poNo","barcode","deliveryType");
        super.setParamsModel(model);
    }

    @ApiOperation("刷新进度状态")
    @RequestMapping(value = "updateProcessStatus",method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse updateProcessStatus(@RequestBody WpSummary model, HttpServletRequest request){
        try {
            if(StringUtils.isEmpty(model.getBillNumber())){
                return new ObjectDataResponse(500,"账单编码不能为空");
            }

            iWpSummaryService.updateProcessStatus(model);
            return new ObjectDataResponse(200,"更新成功");
        } catch (Exception ex){
            log.info("更新数据异常",ex);
            return new ObjectDataResponse(500,"更新失败，请联系管理员！");
        }
    }

    @ApiOperation("财务确认")
    @RequestMapping(value = "sign",method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse sign(@RequestBody WpSummary model, HttpServletRequest request){
        try {

            if(StringUtils.isEmpty(model.getBillNumber())){
                return new ObjectDataResponse(500,"账单编码不能为空");
            }

            String message = iWpSummaryService.sign(model);
            if(!StringUtils.isEmpty(message)){
                return new ObjectDataResponse(500,message);
            }
            return new ObjectDataResponse(200,"更新成功");
        } catch (Exception ex){
            log.info("更新数据异常",ex);
            return new ObjectDataResponse(500,"更新失败，请联系管理员！");
        }
    }

    @ApiOperation("删除操作")
    @RequestMapping(value = "doDelete",method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse doDelete(@RequestBody Map<String,Object>params){
        try {
            setParamsModel(params);
            String billNumber = (String) params.get("billNumber");
            if(StringUtils.isEmpty(billNumber)){
                return new ObjectDataResponse(500,"账单编码不能为空");
            }
            String message = iWpSummaryService.doDelete(params);
            if(!StringUtils.isEmpty(message)){
                return new ObjectDataResponse(500,message);
            }
            return new ObjectDataResponse(200,"更新成功");
        } catch (Exception ex){
            log.info("更新数据异常",ex);
            return new ObjectDataResponse(500,"更新失败，请联系管理员！");
        }
    }


    @ApiOperation("下载账单")
    @RequestMapping(value = "download",method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse download(@RequestBody WpSummary model, HttpServletRequest request){
        try {

            if(StringUtils.isEmpty(model.getShopNo())){
                return new ObjectDataResponse(500,"店铺编码不能为空");
            }

            String[] shopNos = model.getShopNo().split(",");
            List<String> vendorCodes = iTblWpVendorConfigService.getVendorCodes(Arrays.asList(shopNos));
            iWpSummaryService.download(vendorCodes);
            return new ObjectDataResponse(200,"执行成功");
        } catch (Exception ex){
            log.info("下载账单异常",ex);
            return new ObjectDataResponse(500,"下载账单失败，请联系管理员！");
        }
    }
}
